gdkwindow: Handle references in "update_windows" list correctly
authorMarek Kasik <mkasik@redhat.com>
Thu, 12 Dec 2013 14:02:19 +0000 (15:02 +0100)
committerMarek Kasik <mkasik@redhat.com>
Mon, 16 Dec 2013 16:58:04 +0000 (17:58 +0100)
Since update_windows list is a static variable in GdkWindow.c which
contains pointers to windows which needs to be updated, it can happen
that it contains a pointer to a window even after quit from a gtk_main().
If another gtk_main() is called in the same process it tries to process
windows in the list which leads to a crash.
Correct reference count handling of added windows prevents such applications
from crash.

https://bugzilla.gnome.org/show_bug.cgi?id=711552

gdk/gdkwindow.c

index 5f4f7f97c13a813ca87aadfd9dc6576b56f0c4a9..424b82423d64f1619908cc05c6de2d72ae62238f 100644 (file)
@@ -3252,7 +3252,7 @@ gdk_window_add_update_window (GdkWindow *window)
              prev = tmp;
            }
          /* here, tmp got advanced past all lower stacked siblings */
-         tmp = g_slist_prepend (tmp, window);
+         tmp = g_slist_prepend (tmp, g_object_ref (window));
          if (prev)
            prev->next = tmp;
          else
@@ -3265,7 +3265,7 @@ gdk_window_add_update_window (GdkWindow *window)
        */
       if (has_ancestor_in_list && gdk_window_is_ancestor (tmp->data, window))
        {
-         tmp = g_slist_prepend (tmp, window);
+         tmp = g_slist_prepend (tmp, g_object_ref (window));
 
          if (prev)
            prev->next = tmp;
@@ -3279,7 +3279,7 @@ gdk_window_add_update_window (GdkWindow *window)
        */
       if (! tmp->next && has_ancestor_in_list)
        {
-         tmp = g_slist_append (tmp, window);
+         tmp = g_slist_append (tmp, g_object_ref (window));
          return;
        }
 
@@ -3290,13 +3290,20 @@ gdk_window_add_update_window (GdkWindow *window)
    *  hierarchy than what is already in the list) or the list is
    *  empty, prepend
    */
-  update_windows = g_slist_prepend (update_windows, window);
+  update_windows = g_slist_prepend (update_windows, g_object_ref (window));
 }
 
 static void
 gdk_window_remove_update_window (GdkWindow *window)
 {
-  update_windows = g_slist_remove (update_windows, window);
+  GSList *link;
+
+  link = g_slist_find (update_windows, window);
+  if (link != NULL)
+    {
+      update_windows = g_slist_delete_link (update_windows, link);
+      g_object_unref (window);
+    }
 }
 
 static gboolean
@@ -3579,8 +3586,6 @@ gdk_window_process_all_updates (void)
 
   before_process_all_updates ();
 
-  g_slist_foreach (old_update_windows, (GFunc)g_object_ref, NULL);
-
   while (tmp_list)
     {
       GdkWindow *window = tmp_list->data;